home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 007 / a86v307c.arc / 11MACRO.DOC < prev    next >
Encoding:
Text File  |  1987-04-09  |  26.3 KB  |  683 lines

  1. CHAPTER 11   MACROS AND CONDITIONAL ASSEMBLY              11-1
  2.  
  3. Macro Facility
  4. ----- --------
  5.  
  6. A86 contains an easy-to-use, but very powerful macro facility.  
  7. The facility subsumes the capabilities of most assemblers, 
  8. including operand concatenation, indefinite repeat (often called 
  9. IRP), and indefinite-repeat character (IRPC).  Unlike other 
  10. assemblers, A86 integrates these functions into the main macro 
  11. facility; so they can be invoked without clumsy syntax, or 
  12. strange characters in the macro-call operands.  
  13.  
  14.  
  15. Simple Macro Syntax
  16.  
  17. All macros must be defined before they are used.  A macro 
  18. definition consists of the name of the macro, followed by the 
  19. word MACRO, followed by the text of the macro, followed by #EM, 
  20. which marks the end of the macro.  
  21.  
  22. Many assembly languages require a list of dummy operand-names to 
  23. follow the word MACRO.  A86 does not: the operands are denoted in 
  24. the text with the fixed names #1, #2, #3, ... up to a limit of 
  25. #9, for each operand in order.  If there is anything following 
  26. the word MACRO, it is considered part of the macro text.  
  27.  
  28. Examples:
  29.  
  30. ; CLEAR sets the register-operand to zero.
  31.  
  32. CLEAR  MACRO  SUB #1,#1 #EM
  33.  
  34.   CLEAR AX        ; generates a SUB AX,AX instruction
  35.   CLEAR BX        ; generates a SUB BX,BX instruction
  36.  
  37. ; MOVM moves the second operand to the first operand.  Both operands can be
  38. ;   memory-variables.
  39.  
  40. MOVM  MACRO
  41.   MOV AL,#2
  42.   MOV #1,AL
  43. #EM
  44.  
  45. VAR1  DB  ?
  46. VAR2  DB  ?
  47.  
  48. MOVM VAR1,VAR2    ; generates MOV AL,VAR2 followed by MOV VAR1,AL
  49.                                                           11-2
  50. Formatting in macro definitions and calls
  51.  
  52. The format of a macro definition is flexible.  If the macro text 
  53. consists of a single instruction, the definition can be given in 
  54. a single line, as in the CLEAR macro given above.  There is no 
  55. particular advantage to doing this, however: the assembler prunes 
  56. all unnecessary spaces, blank lines, and comments from the macro 
  57. text before entering the text into the symbol table.  I recommend 
  58. the more spread-out format of the MOVM macro, for program 
  59. readability.  
  60.  
  61. All special macro-operators within a macro definition begin with 
  62. a pound-sign #.  The letters following the pound-sign can be 
  63. given in either upper-case or lower-case.  Pound-sign operators 
  64. are recognized even within quoted strings.  If you wish the 
  65. pound-sign to be treated literally, and not as the start of a 
  66. special macro-operator, you must give 2 consecutive pound signs: 
  67. ##.  For example: 
  68.  
  69. FOO MACRO
  70.   DB '##1'
  71.   DB '#1'
  72. #em
  73.  
  74. FOO abc      ; produces  DB '#1'  followed by  DB 'abc'
  75.  
  76. The format of the macro call line is also flexible.  A macro call 
  77. consists of the name of the macro, followed by the operands to be 
  78. plugged into the macro.  The assembler prunes leading and 
  79. trailing blanks from the operands of a macro call.  The operands 
  80. to a macro call are always separated by commas.  Also, as in all 
  81. assembler source lines, a semi-colon occurring outside of a 
  82. quoted-string is the start of a comment, ignored by the 
  83. assembler.  If you want to include commas, blanks, or semi-colons 
  84. in your operands, you must enclose your operand in single-quotes.  
  85.  
  86.  
  87.  
  88. Macro operand substitution
  89.  
  90. Some macro assemblers expect the operands to macro calls to 
  91. follow the same syntax as the operands to instructions.  In those 
  92. assemblers, the operands are parsed, and reduced to numeric 
  93. values before being plugged into the macro definition text.  This 
  94. is called "passing by value".  A86 does not pass by value, it 
  95. passes by text.  The only parsing of operands done by the macro 
  96. processor is to determine the start and the finish of the operand 
  97. text.  That text is substituted, without regard for its contents, 
  98. for the "#n" that appears in the macro definition.  The text is 
  99. interpreted by the assembler only after a complete line is 
  100. expanded and as it is assembled.  
  101.                                                           11-3
  102. If the first non-blank character after the macro name is a comma, 
  103. then the first operand is null: any occurrences of #1 in the 
  104. macro text will be deleted, and replaced with nothing.  Likewise, 
  105. any two consecutive commas with no non-blanks between them will 
  106. result in the corresponding null operand.  Also, out-of-range 
  107. operands are null; for example, #3 is a null operand if only two 
  108. operands are provided in the call.  
  109.  
  110. Null operands to macros are not in themselves illegal.  They will 
  111. produce errors only if the resulting macro expansion is illegal.  
  112.  
  113. The method of passing by text allows operand-text to be plugged 
  114. anywhere into a macro, even within symbol names.  For example: 
  115.  
  116. ; KF_ENTRY creates an entry in the KFUNCS table, consisting of a 
  117. ;   pointer to a KF_-action-routine.  It also declares the 
  118. ;   corresponding CF_-symbol, which is the index within the table 
  119. ;   for that entry.  
  120.  
  121. KF_ENTRY  MACRO
  122.   CF_#1  EQU  ($-KFUNCS)/2+080
  123.   DW  KF_#1
  124. #EM
  125.  
  126. KFUNCS:
  127.   KF_ENTRY  UP
  128.   KF_ENTRY  DOWN
  129.  
  130. ; The above code is equivalent to:
  131. ;
  132. ;  KFUNCS:
  133. ;    DW KF_UP
  134. ;    DW KF_DOWN
  135. ;
  136. ;  CF_UP    EQU  080
  137. ;  CF_DOWN  EQU  081
  138.  
  139.  
  140.  
  141. Quoted-string operands
  142.  
  143. As mentioned before, if you want to include blanks, commas, or 
  144. semicolons in your operands, you enclose the operand in single-
  145. quotes.  In the vast majority of cases in which these special 
  146. characters need to be part of operands, the user wants them to be 
  147. quoted in the final, assembled line also.  Therefore, the quotes 
  148. are passed in the operand.  To override this, and strip the 
  149. quotes from the string, you precede the quoted string with a 
  150. pound-sign.  Examples: 
  151.                                                           11-4
  152. DBW  MACRO
  153.   DB  #1
  154.   DW  #2
  155. #EM
  156.  
  157. DBW  'E', E_POINTER
  158. DBW  'W', W_POINTER
  159.  
  160. ; note that if quotes were not passed, the above lines would have 
  161. ;   to be   DBW  '''E''', E_POINTER;    DBW  '''W''', W_POINTER 
  162.  
  163. GENERAL_PUSH  MACRO
  164.   PUSH#1
  165. #EM
  166.  
  167. GENERAL_PUSH  F        ; generates a PUSHF instruction
  168. GENERAL_PUSH  #' AX'   ; generates a PUSH AX instruction
  169.  
  170. The fact that I could not come up with a more useful example than 
  171. GENERAL_PUSH is strong evidence that it is much better to pass 
  172. the quotes as the default action.  
  173.  
  174.  
  175. Looping by operands in macros
  176.  
  177. This macro facility contains two kinds of loops: you can loop 
  178. once for each operand in a range of operands; or you can loop 
  179. once for each character within an operand.  The first kind of 
  180. loop, the R-loop, is discussed in this section; the second kind, 
  181. the C-loop, is discussed later.  
  182.  
  183. An R-loop is a stretch of macro-definition code that is repeated 
  184. when the macro is expanded.  In addition to the fixed operands #1 
  185. through #9, you can specify a variable operand, whose number 
  186. changes each time through the loop.  You give the variable 
  187. operand one of the 4 names #W, #X, #Y, or #Z.  
  188.  
  189. An R-loop begins with #R, followed immediately by the letter 
  190. W,X,Y, or Z naming the variable, followed by the number of the 
  191. first operand to be used, followed by the number of the last 
  192. operand to be used.  After the #Rxnn is the text to be repeated.  
  193. The R-loop ends with #ER.  For example: 
  194.  
  195. STORE3 MACRO
  196.   MOV AX,#1
  197. #RY24               ; "repeat for Y running from 2 through 4"
  198.   MOV #Y,AX
  199. #ER
  200. #EM
  201.  
  202. STORE3  VAR1,VAR2,VAR3,VAR4
  203.  
  204. ; the above call produces the 4 instructions MOV AX,VAR1; MOV VAR2,AX;
  205. ;   MOV VAR3,AX; MOV VAR4,AX.
  206.                                                           11-5
  207. The #L last operator and indefinite repeats
  208.  
  209. The macro facility recognizes the special operator #L, which is 
  210. the last operand in a macro call.  #L can appear anywhere in 
  211. macro text; but its big power occurs in conjunction with R-loops, 
  212. to yield an indefinite-repeat facility.  
  213.  
  214. A common example is as follows: you can take any macro that is 
  215. designed for one operand, and easily convert it into a macro that 
  216. accepts any number of operands.  You do this by placing the 
  217. command #RX1L, "repeat for X running from 1 through L", at the 
  218. start of the macro, and the command #ER at the end just before 
  219. the #EM.  Finally, you replace all instances of #1 in the macro 
  220. with #X.  We see how this works with the CLEAR macro: 
  221.  
  222. CLEAR MACRO #RX1L
  223.   SUB #X,#X
  224. #ER
  225. #EM
  226.  
  227. CLEAR  AX,BX   ; generates both SUB AX,AX and SUB BX,BX in one 
  228.   macro!
  229.  
  230. It is possible for R-loops to iterate zero times.  In this case, 
  231. the loop-text is skipped completely.  For example, CLEAR without 
  232. any operands would produce no expanded text.  
  233.  
  234.  
  235. Character-loops
  236.  
  237. We have seen the R-loop; now we discuss the other kind of loop in 
  238. macros, the character-loop, or C-loop.  In the C-loop, the 
  239. variable W,X,Y, or Z does not represent an entire operand; it 
  240. represents a character within an operand.  
  241.  
  242. You start a C-loop with #C, followed by one of the 4 letters 
  243. W,X,Y, or Z, followed by a single operand-specifier.  Following 
  244. the #Cxn is the text of the C-loop.  The C-loop ends with #EC.  
  245. The macro will loop once for every character in the operand.  
  246. That single character will be substituted for each instance of 
  247. the indicated variable-operand.  For example: 
  248.  
  249. PUSHC  MACRO  #CW1
  250.   PUSH #WX
  251. #EC#EM
  252.  
  253. PUSHC ABC ; generates the 3 instructions PUSH AX; PUSH BX; PUSH CX
  254.  
  255. If the C-operand is quoted in the macro call, the quotes ARE 
  256. removed from the operand before passing characters to the loop.  
  257. It is not necessary to precede the quoted string with a pound-
  258. sign in this case.  If you do, the pound-sign will be passed as 
  259. the first character.  
  260.  
  261. If the C-operand is a null operand (no characters in it), the 
  262. loop-text is skipped completely.  
  263.                                                           11-6
  264. The "B"-before and "A"-after operators
  265.  
  266. So far, we have seen that you can specify operands in your macro 
  267. in fourteen different ways: 1,2,3,4,5,6,7,8,9,W,X,Y,Z,L.  We now 
  268. multiply these 14 possibilities, by introducing the "A" and "B" 
  269. operators.  You can precede any of the 14 specifiers with "A" or 
  270. "B", to get the adjacent operand after or before the specified 
  271. operand.  For example, BL means the operand just before the last 
  272. operand; in other words, the second-to-the-last operand.  AZ 
  273. means the operand just after the Z operand.  You can even repeat, 
  274. up to a limit of 4 "B"s or 3 "A"s:  BBL is the third-to-last 
  275. operand; #AAA9 can be used where you would want to (but cannot) 
  276. use #12.  
  277.  
  278. In the case of the variable operand to a C-loop, the "A" and "B" 
  279. specifiers denote the characters before or after the current 
  280. looping-character.  An example of this is given in the next 
  281. section.  
  282.  
  283.  
  284. Multiple-increments within loops
  285.  
  286. We have seen that you end an R-loop with a #ER, and you end a C-
  287. loop with a #EC.  We now present another way to end these loops; 
  288. a way that lets you specify a larger increment to the macro's 
  289. loop-counter.  You can end your loops with one of the 4 
  290. additional commands #E1, #E2, #E3, or #E4.  
  291.  
  292. For R-loops terminated by #ER, the variable-operand advances to 
  293. the next operand when the loop is made.  If you end your R-loop 
  294. with #E2, the variable-operand advances 2 operands, not just one.  
  295. For #E3, it advances 3 operands; for #E4, 4 operands.  The #E1 
  296. command is the same as #ER.  
  297.  
  298. The most common usage of this feature is as follows:  You will 
  299. recall that we generalized the CLEAR macro with an R-loop, so 
  300. that it would take an indefinite number of operands.  Suppose we 
  301. want to do the same thing with the DBW macro.  We would like DBW 
  302. to take any number of operands, and alternate DBs and DWs 
  303. indefinitely on the operands.  This is made possible by creating 
  304. an R-loop terminated by #E2: 
  305.  
  306. DBW  MACRO  #RX1L
  307.   DB  #X
  308.   DW  #AX
  309. #E2
  310. #EM
  311.  
  312. DBW  'E',E_POINTER,  'W',W_POINTER   ; two pairs on same line!
  313.  
  314. The #E2 terminator means that we are looping on a pair of 
  315. operands.  Note the crucial usage of the "A"-after operator to 
  316. specify the second operand of the operand-pair.  
  317.                                                           11-7
  318. A special note applies to the DBW macro above: the assembler just 
  319. happens to accept a DW directive with no operands (it generates 
  320. no object code, and issues no error).  This means that DBW will 
  321. accept an odd number of operands with no error, and do the 
  322. expected thing (it alternates bytes and words, ending with a 
  323. byte).  
  324.  
  325. You could likewise generalize a macro with 3 or 4 operands, to an 
  326. indefinite number of triples or quadruples; by ending the R-loop 
  327. with #E3 or #E4.  The operands in each group would be specified 
  328. by #X, #AX, #AAX, and, for #E4, #AAAX.  
  329.  
  330. For C-loops terminated by #E1 through #E4, the character-pointer 
  331. is advanced the specified number of characters.  You use this in 
  332. much the same way as for R-loops, to create loops on pairs, 
  333. triplets, and quadruplets of characters.  For example: 
  334.  
  335. PUSHC2  MACRO  #CZ1
  336.   PUSH #Z#AZ
  337. #E2
  338. #EM
  339.  
  340. PUSHC2  AXBXSIDI    ; generates PUSH AX; PUSH BX; PUSH SI; PUSH DI
  341.  
  342.  
  343. Negative R-loops
  344.  
  345. We now introduce another form of R-loop, called the Q-loop-- the 
  346. negative repeat-loop.  This loop is the same as the R-loop, 
  347. except that the operand number decrements instead of increments; 
  348. and the loop exits when the number falls below the finish-number, 
  349. not above it.  The Q-loop is specified by #Qxnn instead of #Rxnn, 
  350. and #EQ instead of #ER.  You can also use the multiple-decrement 
  351. forms #E1 #E2 #E3 or #E4 to terminate an Q-loop.  
  352.  
  353. Example:
  354.  
  355. MOVN MACRO #QXL2   ; "negative-repeat X from L down to 2"
  356.   MOV #BX,#X
  357. #EQ#EM
  358.  
  359. MOVN AX,BX,CX,DX    ; generates the three instructions:
  360.                     ;    MOV CX,DX
  361.                     ;    MOV BX,CX
  362.                     ;    MOV AX,BX
  363.  
  364. Note: the above functionality is already built into the MOV 
  365. instruction of the assembler.  The macro shows how you would 
  366. implement it if you did not already have this facility.  
  367.  
  368.  
  369. Nesting of loops in macros
  370.  
  371. This macro facility allows nesting of loops within each other.  
  372. Since we provide the 4 identifiers W,X,Y,Z for the loop-operands, 
  373. you can nest to a level of 4 without restriction-- just use a 
  374. different letter for each nesting level.  You can nest even 
  375. deeper, subject to the restriction that a letter W,X,Y,Z refers 
  376. to the innermost containing loop that defines it.  
  377.                                                           11-8
  378. Implied closing of loops
  379.  
  380. If you have a loop or loops ending when the macro ends, and if 
  381. the iteration count for those loops is 1, you may omit the #ER, 
  382. #EC, or #EQ.  The assembler closes all open loops when it sees 
  383. #EM, with no error.  
  384.  
  385. For example, if you omit the #ER for the loop-version of the 
  386. CLEAR macro, it would make no difference-- the assembler 
  387. automatically places an #ER code into the macro definition for 
  388. you.  
  389.  
  390.  
  391. Local labels in macros
  392.  
  393. Some assemblers have a LOCAL pseudo-op that is used in 
  394. conjunction with macros.  Symbols declared LOCAL to a macro have 
  395. unique (and bizarre) symbol-names substituted for them each time 
  396. the macro is called.  This solves the problem of duplicate label 
  397. definitions when a macro is called more than once.  
  398.  
  399. In A86, the problem is solved more elegantly, by having a class 
  400. of generic local labels throughout assembly, not just in macros.  
  401. Recall that symbols consisting of a single letter, followed by 
  402. one or more decimal digits, can be redefined.  You can use such 
  403. labels in your macro definitions.  
  404.  
  405. I have recommended that local labels outside of macros be 
  406. designated L1 through L9.  Within macro definitions, I suggest 
  407. that you use labels M1 through M9.  If you used an Ln-label 
  408. within a macro, you would have to make sure that you never call 
  409. the macro within the range of definition of another Ln-label with 
  410. the same name.  By using Mn-labels, you avoid such potential 
  411. conflicts.  
  412.  
  413. The following example of a local label within a macro is taken 
  414. from the source of the macro-processor itself: 
  415.                                                           11-9
  416. ; "JPOUND label" checks to see if AL is a pound sign.  If it is, 
  417. ;    it processes the pound-sign term, and jumps to label.  
  418. ;    Otherwise, it drops through to the following code.  
  419.  
  420. JPOUND MACRO
  421.   CMP AL,'##'         ; is the scanned character a pound-sign?
  422.   JNE >M1             ; skip if not
  423.   CALL MDEF_POUND     ; process the pound sign
  424.   JMP #1              ; jump to the label provided
  425. M1:
  426.   #EM
  427.  
  428.   ...
  429. L3:                   ; loop here to eat empty lines, leading blanks
  430.   CALL SKIP_BLANKS    ; skip over the leading blanks of a line
  431.   INC SI              ; advance source ptr beyond the next non-blank
  432.   JPOUND L3           ; if pound-sign then process, and eat more blanks
  433.   CMP AL,0A           ; were the blanks terminated by a linefeed?
  434.   JE L3               ; loop if yes, nothing on this line
  435. L5:                   ; loop here after a line is seen to have contents
  436.   CMP AL,';'          ; have we reached the start of a comment?
  437.   JE L1               ; jump if yes, to consume the comment
  438.   JPOUND >L6          ; if pound-sign then process it; get next char
  439.   ...
  440. L6:
  441.   LODSB               ; fetch the next definition-char from the source
  442.   CMP AL,' '          ; is it blank?
  443.   JA L5               ; loop if not, to process it
  444.   ...
  445.  
  446.  
  447. Debugging macro expansions
  448.  
  449. There is a tool called EXMAC which will help you troubleshoot 
  450. program lines that call macros.  If you are not sure about what 
  451. code is being generated by your macro calls, EXMAC will tell you.  
  452. See Chapter 13 for details.  
  453.                                                           11-10
  454. Conditional Assembly
  455. ----------- --------
  456.  
  457. A86 has a conditional assembly feature, that allows you to 
  458. specify that blocks of source code will or will not be assembled, 
  459. according to the values of equated user symbols.  The controlling 
  460. symbols can be declared in the program (and can thus be the 
  461. result of assembly-time expressions), or they can be declared in 
  462. the assembler invocation.  
  463.  
  464. You should keep in mind the difference between conditional 
  465. assembly, invoked by #IF, and the structured-programming feature, 
  466. invoked by IF without the pound-sign.  #IF tests a condition at 
  467. assembly-time, and can cause code to not be assembled and thus 
  468. not appear in the program.  IF causes code to be assembled that 
  469. tests a condition at run-time, possibly jumping over code.  The 
  470. skipped code will always appear in the program.  
  471.  
  472. All conditional assembly lines are identified by a pound-sign # 
  473. as the first non-blank character of a line.  The pound-sign is 
  474. followed by one of the four keywords IF, ELSEIF, ELSE or ENDIF.  
  475.  
  476. #IF starts a conditional-assembly block.  On the same line, 
  477. following the #IF, you provide a name.  If the name is undefined, 
  478. or if it has been equated to zero, then the following lines of 
  479. code are skipped, up to the next matching #ELSEIF, #ELSE, or 
  480. #ENDIF.  If the name is non-zero, then the following lines of 
  481. code are assembled normally.  If a subsequent matching #ELSEIF or 
  482. #ELSE is encountered, then code is skipped up to the matching 
  483. #ENDIF.  
  484.  
  485. #ELSEIF provides a multiple-choice facility for #IF-blocks.  You 
  486. can give any number of #ELSEIFs between an #IF and its matching 
  487. #ENDIF.  Each #ELSEIF has a name following it on the same line.  
  488. If the name following the #IF has zero value, then the assembler 
  489. looks for the first non-zero name following an #ELSEIF, and 
  490. assembles that block of code.  If there are no non-zero #ELSEIFs, 
  491. then the #ELSE-block (if there is one) is assembled.  
  492.  
  493. It is legal to provide an undefined name after #IF or #ELSEIF.  
  494. The name is interpreted as being false (zero), with no error.  
  495.  
  496. You may precede the name in an #IF or #ELSEIF line with an 
  497. exclamation point "!", which acts as a NOT-operator: code will be 
  498. skipped if the name is non-zero instead of zero.  
  499.  
  500. #ELSE marks the beginning of code to be assembled if all the 
  501. previous blocks of an #IF have been skipped over.  There is no 
  502. operand after the #ELSE.  There can be at most one #ELSE in an 
  503. #IF-block, and it must appear after any #ELSEIFs.  
  504.  
  505. #ENDIF marks the end of an #IF-block.  There is no operand after 
  506. #ENDIF.  
  507.  
  508. It is legal to have nested #IF-blocks; that is, #IF-blocks that 
  509. are contained within other #IF-blocks.  #ELSEIF, #ELSE, and 
  510. #ENDIF always refer to the innermost nested #IF-block.  
  511.                                                           11-11
  512. As an example of conditional assembly, suppose that you have a 
  513. program that comes in three versions: one for Texas, one for 
  514. Oklahoma, and one for the rest of the nation.  The three programs 
  515. differ in a limited number of places.  Instead of keeping three 
  516. different versions of the source code, you can keep one version, 
  517. and use conditional assembly on the boolean variables TEXAS and 
  518. OKLAHOMA to control the assembler output.  A sample block would 
  519. be: 
  520.  
  521. #if TEXAS
  522.   DB 0,1,2,3
  523. #elseif OKLAHOMA
  524.   DB 4,5,6,7
  525. #else
  526.   DB 8,9,10,11
  527. #endif
  528.  
  529. If a block of code is to be assembled only if TEXAS is false, 
  530. then you would use the exclamation-point operator: 
  531.  
  532. #if !TEXAS
  533.   DB 0FF
  534. #endif
  535.  
  536.  
  537. Conditional Assembly and Macros
  538.  
  539. You may have conditional-assembly blocks either in macro-
  540. definitions or in macro expansions.  The only limitation is that 
  541. if you have an #IF-block in a macro expansion, the entire block 
  542. (i.e., the matching #ENDIF) must appear in the same macro 
  543. expansion.  You cannot, for example, define a macro that is a 
  544. synonym for #IF.  
  545.  
  546. To have your conditional-assembly block apply to the macro 
  547. definition, you provide the block normally within the definition.  
  548. For example: 
  549.  
  550. X1 EQU 0
  551.   BAZ MACRO
  552. #if X1
  553.   DB 010
  554. #else
  555.   DB 011
  556. #endif
  557. #EM
  558.   BAZ
  559. X1 EQU 1
  560.   BAZ
  561.  
  562. In the above sequence of code, the conditional-assembly block is 
  563. acted upon when the macro BAZ is defined.  The macro therefore 
  564. consists of the single line DB 011, with all the conditional-
  565. assembly lines removed from the definition.  Thus, both 
  566. expansions of BAZ produce the object-code byte of 011, even 
  567. though the local label X1 has turned non-zero for the second 
  568. invocation.  
  569.                                                           11-12
  570. To have your conditional-assembly block appear in the macro 
  571. expansion, you must literalize the pound-sign on each 
  572. conditional-assembly line by giving two pound-signs: 
  573.  
  574. X1 EQU 0
  575.   BAZ MACRO
  576. ##if X1
  577.   DB 010
  578. ##else
  579.   DB 011
  580. ##endif
  581. #EM
  582.   BAZ
  583. X1 EQU 1
  584.   BAZ
  585.  
  586. Now the entire conditional-assembly block is stored in the macro 
  587. definition, and acted upon each time the macro is expanded.  
  588. Thus, the two invocations of BAZ will produce the different 
  589. object bytes 011 and 010, since X1 has become non-zero for the 
  590. second expansion.  
  591.  
  592. You will usually want your conditional-assembly blocks to be 
  593. acted upon at macro-definition time, to save symbol-table space.  
  594. You will thus use the first form, with the single pound-signs.  
  595.  
  596.  
  597. Conditional Assembly and the XREF Program
  598.  
  599. In most cases, the XREF program will recognize conditional-
  600. assembly blocks, and ignore skipped-code in its XREF compilation.  
  601. The last macro example above, however, is an example in which 
  602. XREF will not skip the same blocks that the assembler will; 
  603. because it falls under the following 
  604.  
  605. WARNING: The XREF program will use the value of all symbols as it 
  606.    existed at the end of assembly.  XREF does not parse 
  607.    statements that change the value of local variables!  Thus, if 
  608.    you have conditional assembly based on a variable whose value 
  609.    changes during assembly, XREF will compile different source 
  610.    than the assembler assembled.  
  611.  
  612. The above warning does not apply to invocation-variables, 
  613. described below. If you wish to change the value of a 
  614. conditional-control variable during assembly, and if you wish 
  615. XREF to give accurate results, you should change the variable 
  616. between file-names in the invocation, as described below.  
  617.                                                           11-13
  618. Declaring Variables in the Assembler Invocation
  619.  
  620. To facilitate the effective use of conditional assembly, this 
  621. assembler allows you to declare boolean (true-false) symbols in 
  622. the command-line that invokes the assembler.  The declarations 
  623. can appear anywhere in the list of source file names.  They are 
  624. distinguished from the file names by a leading equals-sign =.  To 
  625. declare a symbol TRUE (value = 1), give the name after the 
  626. equals-sign.  DO NOT put any spaces between the equals-sign and 
  627. the name! To declare a symbol FALSE (value = 0), you can give an 
  628. equals-sign, an exclamation-point, then the name.  Again, DO NOT 
  629. embed any blanks!  Example: if your source files are src1.8, 
  630. src2.8, and src3.8, then you can assemble with TEXAS true by 
  631. invoking the assembler as follows: 
  632.  
  633.    a86 =TEXAS src1.8 src2.8 src3.8
  634.  
  635. You can assemble with TEXAS explicitly set to FALSE as follows:
  636.  
  637.    a86 =!TEXAS src1.8 src2.8 src3.8
  638.  
  639. Note that if TEXAS is used only as a conditional-assembly 
  640. control, then you do not need to include the =!TEXAS in the 
  641. invocation, because an undefined TEXAS will automatically be 
  642. interpreted as false.  
  643.  
  644.  
  645. Null Invocation Variable Names
  646.  
  647. The assembler will ignore an equals-sign by itself in the 
  648. invocation line, without error.  This allows you to generate 
  649. assembler-invocation lines using parameters that could be either 
  650. boolean-variable-names, or null strings. For example, in the 
  651. previously-mentioned TEXAS-OKLAHOMA-nation example, the program 
  652. could be invoked via a .BAT file called "AMAKE.BAT", coded as 
  653. follows: 
  654.  
  655.       A86 =%1 *.8
  656.  
  657. You invoke the assembler by typing one of the following:
  658.  
  659.       amake texas
  660.       amake oklahoma
  661.       amake
  662.  
  663. The third line will produce the assembler-invocation  A86 = *.8; 
  664. causing no invocation-variables to be declared.  Thus both TEXAS 
  665. and OKLAHOMA will be false, which is exactly what you want for 
  666. the rest-of-the-nation version of the program.  
  667.                                                           11-14
  668. Changing Values of Invocation Variables
  669.  
  670. The usual prohibition against changing the value of a symbol that 
  671. is not a local-label does not apply to invocation-variables.  For 
  672. example, suppose you have a conditional-control variable DEBUG, 
  673. which will generate diagnostic code for debugging when it is 
  674. true.  Suppose further that you have already debugged source 
  675. files src1.8 and src3.8; but you are still working on src2.8. You 
  676. may invoke the assembler as follows: 
  677.  
  678.    A86 src1.8 =DEBUG src2.8 =!DEBUG src3.8
  679.  
  680. The variable DEBUG will be TRUE only during assembly of src2.8, 
  681. just as you want.  
  682.  
  683.